// Copyright (C) 1953-2022 NUDT
// Verilog module name - st_overflow_monitor
// Version: TOM_V1.0
// Created:
//         by - fenglin 
//         at - 9.2022
////////////////////////////////////////////////////////////////////////////
// Description:
//         - monitor whether TS packet is overflow;
//         - transmit nmac packet to CSM.
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps
 
module st_overflow_monitor
(
       i_clk,
       i_rst_n,
       
       iv_data         ,
       i_data_wr       ,
       iv_ipv          ,       
       iv_inject_dbufid,
       
       iv_st_stream_state,
       o_pkt_cnt_pulse,
       
       ov_data,
       o_data_wr,
       ov_ipv,       
       ov_inject_dbufid ,   
       
       o_st_overflow_error_pulse      
);

// I/O
// clk & rst
input                  i_clk           ;
input                  i_rst_n         ;  
// pkt input
(*MARK_DEBUG="true"*)input      [8:0]       iv_data         ;
(*MARK_DEBUG="true"*)input                  i_data_wr       ;
(*MARK_DEBUG="true"*)input      [2:0]       iv_ipv          ;       
(*MARK_DEBUG="true"*)input      [4:0]       iv_inject_dbufid;
//TS traffic state
(*MARK_DEBUG="true"*)input      [31:0]      iv_st_stream_state;
output reg             o_pkt_cnt_pulse   ;
// pkt output
output reg [8:0]       ov_data           ;
output reg             o_data_wr         ;
output reg [2:0]       ov_ipv            ;
output reg [4:0]       ov_inject_dbufid  ;
//count overflow error of 32 TS flow 
output reg             o_st_overflow_error_pulse;
//***************************************************
//        judge whether TS traffic is overflow 
//***************************************************
// internal reg&wire for state machine
(*MARK_DEBUG="true"*)reg                    r_st_overflow_flag;
(*MARK_DEBUG="true"*)reg        [4:0]       rv_st_injection_addr;
(*MARK_DEBUG="true"*)reg        [1:0]       SOM_STATE;
localparam  IDLE_S       = 2'd0,
            TRANS_DATA_S = 2'd1,
            DISC_DATA_S  = 2'd2;
always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n) begin        
        ov_data           <= 9'b0;
        o_data_wr         <= 1'b0;
        ov_ipv            <= 3'b0;
        ov_inject_dbufid  <= 5'b0;
        
        o_pkt_cnt_pulse   <= 1'b0;
        
        r_st_overflow_flag        <= 1'b0;
        rv_st_injection_addr      <= 5'b0;
        
        SOM_STATE                 <= IDLE_S;
    end
    else begin
        case(SOM_STATE)
            IDLE_S:begin
                if(i_data_wr == 1'b1 && iv_data[8] == 1'b1)begin
                    o_pkt_cnt_pulse <= 1'b1;
                    if((iv_ipv == 3'h5) || (iv_ipv == 3'h6) || (iv_ipv == 3'h7))begin//st
                        if(|((32'h1 << iv_inject_dbufid) & iv_st_stream_state)==1'b0)begin //not overflow
                            ov_data      <= iv_data;
                            o_data_wr    <= 1'b1;
                            ov_ipv            <= iv_ipv;
                            ov_inject_dbufid  <= iv_inject_dbufid;
                            SOM_STATE    <= TRANS_DATA_S;
                        end
                        else begin
                            r_st_overflow_flag   <= 1'b1;
                            rv_st_injection_addr <= iv_inject_dbufid;
                            ov_data              <= 9'b0;
                            o_data_wr            <= 1'b0;
                            ov_ipv               <= 3'b0;
                            ov_inject_dbufid     <= 5'b0;                            
                            SOM_STATE            <= DISC_DATA_S;
                        end                     
                    end
                    else begin
                        ov_data    <= iv_data;
                        o_data_wr  <= 1'b1;
                        ov_ipv            <= iv_ipv;
                        ov_inject_dbufid  <= iv_inject_dbufid;
                        SOM_STATE <= TRANS_DATA_S;                      
                    end 
                end
                else begin
                    ov_data <= 9'b0;
                    o_data_wr <= 1'b0;
                    ov_ipv               <= 3'b0;
                    ov_inject_dbufid     <= 5'b0; 
                    
                    o_pkt_cnt_pulse <= 1'b0;
                    
                    r_st_overflow_flag <= 1'b0;
                    rv_st_injection_addr <= 5'b0;
                    
                    SOM_STATE <= IDLE_S;                    
                end
            end
            TRANS_DATA_S:begin 
                ov_data <= iv_data;
                o_data_wr <= i_data_wr;
                o_pkt_cnt_pulse <= 1'b0;
                if(i_data_wr == 1'b1 && iv_data[8] == 1'b1)begin
                    SOM_STATE <= IDLE_S;    
                end
                else begin  
                    SOM_STATE <= TRANS_DATA_S;  
                end
            end        
            DISC_DATA_S:begin 
                ov_data <= 9'b0;
                o_data_wr <= 1'b0;
                r_st_overflow_flag <= 1'b0;
                o_pkt_cnt_pulse <= 1'b0;
                if(i_data_wr == 1'b1 && iv_data[8] == 1'b1)begin
                    SOM_STATE <= IDLE_S;    
                end
                else begin  
                    SOM_STATE <= DISC_DATA_S;   
                end
            end         
            default:begin
                ov_data <= 9'b0;
                o_data_wr <= 1'b0;
                
                o_pkt_cnt_pulse <= 1'b0;
                
                SOM_STATE <= IDLE_S;
            end
        endcase
   end
end 
//***************************************************
//      count overflow error of 32 TS flow 
//***************************************************
always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n) begin
        o_st_overflow_error_pulse <= 1'b0;
    end
    else begin
        if(r_st_overflow_flag == 1'b1 && (|((32'h1 << rv_st_injection_addr) & iv_st_stream_state)==1'b1))begin
            o_st_overflow_error_pulse <= 1'b1;           
        end
        else begin
            o_st_overflow_error_pulse <= 1'b0; 
        end        
    end
end
endmodule